查看原文
其他

利用内核知识,自己实现ReadProcessMemory(二)

2018-02-12 五行猫 看雪学院


说了这么多关于表的格式和查表的方法,在实践中我们该如何利用呢?一个用处是我们经常需要把虚拟地址转换成物理地址,明白其转换原理利于分析问题,另外上面说了,每个进程都会有一套自己的分页机制,切换进程实际上是切换CR3中的内容,那么如何实现我们自己的ReadProcessMemory呢?

 

问题变成了以下4步:

  1. 拿到指定进程保存在CR3中的内容

  2. 切换当前的CR3

  3. 读取指定内存的内容

  4. 还原CR3



第一步,如何拿到指定进程保存在CR3中的内容?


我们知道在3环程序里,fs[0]保存的是线程环境块TEB,在0环,保存的则是处理器控制区(_KPCR),部分内核数据结构如下图:

 

从_EPROCESS中的进程链表我们可以遍历所有进程,当匹配到目标进程时,拿出目标进程DirectoryTableBase中保存的地址。


NTSTATUS GetProcessDirBase(IN DWORD dwPID, OUT PDWORD pDirBase)

{

    PEPROCESS Process;

    PEPROCESS CurProcess;

    CHAR  *pszImageName;

    DWORD dwCurPID;

    DWORD i;

 

    __try

    {       

        __asm

        {

            //ETHREAD

            mov eax, fs:[124h]

            //Current EPROCESS

            mov eax, [eax + 44h]

            mov Process, eax

        }

 

        CurProcess = Process;

        i = 0;

        //traversing  EPROCESS

        do

        {

            pszImageName = (char*)CurProcess + 0x174;

            dwCurPID = (*(DWORD*)((char*)CurProcess + 0x084));

 

            if (dwCurPID == dwPID)

            {

                *pDirBase = (*(DWORD*)((char*)CurProcess + 0x018));

                return STATUS_SUCCESS;

            }

             //Next

            CurProcess = (*(DWORD*)((char*)CurProcess + 0x088)) - 0x88;

        } while (CurProcess != Process);

    }

    __except (EXCEPTION_EXECUTE_HANDLER)

    {

        dprintf("[MyReadProcessMemory] GetProcessDirBase __except \r\n");

    }

 

    return STATUS_INVALID_DEVICE_REQUEST;

}



第二步,切换当前的CR3


切换CR3的值之前,我们需要屏蔽调当前CPU核心的中断,以防线程切换,如果是多核的CPU,每个核心都需要屏蔽掉中断。同时,为了预防内存属性不可写,暂时改掉CR0中表示所有内存属性的标志,让所有内存暂时都可写。

__asm

{

    //Shielding interrupt

    cli    

    //close memory protect        

    mov eax, cr0               

    and eax, not 10000h

    mov cr0, eax

    mov eax, cr3

    mov dwOldDirBase, eax

    //swap CR3

    mov eax, dwDirBase

    mov cr3, eax

}



第三步,读取指定内存的内容


申请一段空间,暂存一下读取的数据,记得要检查目标内存地址是否有效

//Alloc ring0 Buff

char* szRing0Buf = (char*)MmAllocateNonCachedMemory(dwBufSize);

//check address invalid

if (MmIsAddressValid(dwTargetAdddress))

{

    RtlCopyMemory(szRing0Buf, dwTargetAdddress, dwBufSize);

    bIsRead = TRUE;

}



第四步,还原CR3


恢复内存属性,恢复中断

__asm

{

    mov eax, dwOldDirBase

    mov cr3, eax

    //Reset  memory protect

    mov eax, cr0               

    or  eax, 10000h

    mov cr0, eax

    //Restore interrupt

    sti                        

}



总结


内核的学习也开始进入尾声,温故而知新,整理知识本身也是一种学习的过程。衷心感谢一年多以来钱老师,张老师,姚老师,戚老师,王老师,唐老师的指导。要毕业了,帮科锐宣传下,科锐30期正在招生中





本文由看雪论坛 五行猫 原创

转载请注明来自看雪社区


热门阅读


点击阅读原文/read,

更多干货等着你~

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存